
#include <stm32f103.h>
#include <rcc.h>

#define RCC_BASE				(AHBPERIPH_BASE + 0x1000)
#define FLASH_R_BASE				(AHBPERIPH_BASE + 0x2000)

#define RCC					((RCC_TypeDef *)RCC_BASE)
#define FLASH					((FLASH_TypeDef *)FLASH_R_BASE)

typedef struct
{
	__IO uint32_t CR;
	__IO uint32_t CFGR;
	__IO uint32_t CIR;
	__IO uint32_t APB2RSTR;
	__IO uint32_t APB1RSTR;
	__IO uint32_t AHBENR;
	__IO uint32_t APB2ENR;
	__IO uint32_t APB1ENR;
	__IO uint32_t BDCR;
	__IO uint32_t CSR;
} RCC_TypeDef;

typedef struct
{
	__IO uint32_t ACR;
	__IO uint32_t KEYR;
	__IO uint32_t OPTKEYR;
	__IO uint32_t SR;
	__IO uint32_t CR;
	__IO uint32_t AR;
	__IO uint32_t RESERVED;
	__IO uint32_t OBR;
	__IO uint32_t WRPR;
} FLASH_TypeDef;

int system_init(void)
{
	__IO uint32_t StartUpCounter = 0;

	RCC->CR |= (uint32_t)0x00000001;
	RCC->CFGR &= (uint32_t)0xF0FF0000;
	RCC->CR &= (uint32_t)0xFEF6FFFF;
	RCC->CR &= (uint32_t)0xFFFBFFFF;
	RCC->CFGR &= (uint32_t)0xFF80FFFF;
	RCC->CIR = (uint32_t)0x009F0000;

	RCC->CR |= ((uint32_t)0x00010000);

	while((0 == (RCC->CR & RCC_CR_HSERDY)) && (StartUpCounter < (uint32_t)0x0500))
	{
		StartUpCounter++;
	}
	
	if(0 != (RCC->CR & RCC_CR_HSERDY))
	{
		FLASH->ACR |= (uint32_t)0x10;
		FLASH->ACR &= ~((uint32_t)0x03);
		FLASH->ACR |= ((uint32_t)0x02);
		
		RCC->CFGR |= (uint32_t)0x00000000;
		RCC->CFGR |= (uint32_t)0x00000000;
		RCC->CFGR |= (uint32_t)0x00000400;
		
		RCC->CFGR &= ~(((uint32_t)0x00010000) | ((uint32_t)0x00020000) | ((uint32_t)0x003C0000));
		RCC->CFGR |= ((uint32_t)0x00010000) | ((uint32_t)0x001C0000);
		
		RCC->CR |= (uint32_t)0x01000000;

		while((RCC->CR & (uint32_t)0x02000000) == 0);

		RCC->CFGR &= ~((uint32_t)0x00000003);
		RCC->CFGR |= (uint32_t)0x00000002;

		while((uint32_t)0x08 != (RCC->CFGR & (uint32_t)0x0000000C));

		return 0;
	}
	else
	{
		return -1;
	}
}

int rcc_enable(unsigned int rcc, unsigned int bit)
{
	switch(rcc)
	{
		case RCC_AHB:
			RCC->AHBENR |= bit;
			break;
		case RCC_APB1:
			RCC->APB1ENR |= bit;
			break;
		case RCC_APB2:
			RCC->APB2ENR |= bit;
			break;
		default:
			return -1;
	}
	return 0;
}

int rcc_disable(unsigned int rcc, unsigned int bit)
{
	switch(rcc)
	{
		case RCC_AHB:
			RCC->AHBENR &= ~bit;
			break;
		case RCC_APB1:
			RCC->APB1RSTR |= bit;
			break;
		case RCC_APB2:
			RCC->APB2RSTR |= bit;
			break;
		default:
			return -1;
	}
	return 0;
}